package com.totem.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.totem.admin.mapper.TAppConfigItemMapper;
import com.totem.admin.mapper.TAppConfigMapper;
import com.totem.admin.model.TAppConfig;
import com.totem.admin.model.TAppConfigItem;
import com.totem.admin.service.ITAppConfigItemService;
import com.totem.admin.service.ITAppConfigService;
import com.totem.admin.vo.AppConfigItemVO;
import com.totem.admin.vo.AppConfigListVO;
import com.totem.admin.vo.AppConfigVO;
import com.totem.admin.vo.UpdateSubscribeVO;
import com.totem.base.constants.CommonConstants;
import com.totem.base.constants.ErrorCode;
import com.totem.base.enums.*;
import com.totem.base.exception.BaseException;
import com.totem.product.mapper.TFundsMapper;
import com.totem.product.mapper.TSubscribeMapper;
import com.totem.product.model.TSubscribe;
import com.totem.product.service.ITSubscribeService;
import com.totem.product.vo.SubscribeVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TAppConfigServiceImpl extends ServiceImpl<TAppConfigMapper, TAppConfig> implements ITAppConfigService {
    @Autowired
    private TAppConfigItemMapper tAppConfigItemMapper;
    @Autowired
    private ITAppConfigItemService itAppConfigItemService;
    @Autowired
    private TSubscribeMapper tSubscribeMapper;
    @Autowired
    private TAppConfigMapper tAppConfigMapper;
    @Autowired
    private ITSubscribeService itSubscribeService;
    @Autowired
    private TFundsMapper tFundsMapper;
    @Autowired
    private Executor asyncExecutor;
    private String collectionAddr;
    private String feePriv;
    private String feeAddr;

    @Override
    public boolean initData() {
        TAppConfig subscribeSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.SUBSCRIBE.getCode())
                .build();
        TAppConfig fundSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.FUND.getCode())
                .build();
        TAppConfig withdrawSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.WITHDRAW.getCode())
                .build();
        TAppConfig collectionSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.COLLECTION.getCode())
                .build();
        TAppConfig chargeSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.CHARGE.getCode())
                .build();
        TAppConfig conversionSettle = TAppConfig.builder()
                .configName(AppConfigNameEnum.CONVERSION.getCode())
                .build();
        List<TAppConfig> appConfigInitData = List.of(subscribeSettle, fundSettle, withdrawSettle, collectionSettle, chargeSettle, conversionSettle);
        LambdaQueryWrapper<TAppConfig> appConfigQuery = new LambdaQueryWrapper<>();
        Long count = baseMapper.selectCount(appConfigQuery);
        if (count >= appConfigInitData.size()) {
            return true;
        }
        boolean appConfigResult = super.saveBatch(appConfigInitData);
        if (!appConfigResult) {
            return false;
        }
        TAppConfigItem subscribeItemShowSettle = TAppConfigItem.builder()
                .configId(subscribeSettle.getId())
                .itemName(SubscribeNameEnum.SUBSCRIBE_SHOW_SPECIAL.getCode())
                .itemValue(SwitchEnum.ON.getCode())
                .remark("特殊认购包显示")
                .build();

        TAppConfigItem fundGameSettle = TAppConfigItem.builder()
                .configId(fundSettle.getId())
                .itemName(AppConfigItemNameEnum.FUND_RETURN_RATE.getCode())
                .itemValue("0.005")
                .remark("完成质押时,次日结算所对应的奖励比例(%)")
                .build();
        TAppConfigItem fundWithdrawSettle = TAppConfigItem.builder()
                .configId(fundSettle.getId())
                .itemName(AppConfigItemNameEnum.FUND_WITHDRAW_FEE.getCode())
                .itemValue("0.01")
                .remark("提取质押时,扣除的比例(%)")
                .build();

        TAppConfigItem withdrawLowestSettle = TAppConfigItem.builder()
                .configId(withdrawSettle.getId())
                .itemName(AppConfigItemNameEnum.WITHDRAW_MIN.getCode())
                .itemValue("100")
                .remark("确认提现时,最低的固定额度")
                .build();
        TAppConfigItem withdrawHighestSettle = TAppConfigItem.builder()
                .configId(withdrawSettle.getId())
                .itemName(AppConfigItemNameEnum.WITHDRAW_MAX.getCode())
                .itemValue("10000")
                .remark("确认提现时,最高的固定额度")
                .build();
        TAppConfigItem withdrawChargeSettle = TAppConfigItem.builder()
                .configId(withdrawSettle.getId())
                .itemName(AppConfigItemNameEnum.WITHDRAW_FEE.getCode())
                .itemValue("0.01")
                .remark("提现时,扣除的比例(%)")
                .build();

        TAppConfigItem collectionAddressSettle = TAppConfigItem.builder()
                .configId(collectionSettle.getId())
                .itemName(AppConfigItemNameEnum.USDT_COLLECTION_ADDR.getCode())
                // todo
                .itemValue("0x07a48510445C4D33C95bF1B9859BA0F9D6941668")
                .remark("USDT归集地址")
                .build();

        TAppConfigItem chargePrivSettle = TAppConfigItem.builder()
                .configId(chargeSettle.getId())
                .itemName(AppConfigItemNameEnum.CHARGE_PRIVATE_KEY.getCode())
                // todo
                .itemValue("e929e6855f0b236ea0c653d9851c4963e81990edc0f4565d2f4b9806950992b6")
                .remark("手续费-私钥")
                .build();
        TAppConfigItem chargeAddrSettle = TAppConfigItem.builder()
                .configId(chargeSettle.getId())
                .itemName(AppConfigItemNameEnum.CHARGE_ADDRESS.getCode())
                // todo
                .itemValue("0x07a48510445C4D33C95bF1B9859BA0F9D6941668")
                .remark("手续费-地址")
                .build();

        TAppConfigItem conversionBalanceSettle = TAppConfigItem.builder()
                .configId(conversionSettle.getId())
                .itemName(AppConfigItemNameEnum.BALANCE_CONVERSION_FEE.getCode())
                .itemValue("0.05")
                .remark("转化成功时, 扣除的比例(%)")
                .build();

        List<TAppConfigItem> appConfigItemInitData = List.of(subscribeItemShowSettle,
                fundGameSettle, fundWithdrawSettle,
                withdrawLowestSettle, withdrawHighestSettle, withdrawChargeSettle,
                collectionAddressSettle,
                chargePrivSettle, chargeAddrSettle,
                conversionBalanceSettle
        );
        LambdaQueryWrapper<TAppConfigItem> appConfigItemQuery = new LambdaQueryWrapper<>();
        Long itemCount = tAppConfigItemMapper.selectCount(appConfigItemQuery);
        if (itemCount >= appConfigItemInitData.size()) {
            return true;
        }
        return itAppConfigItemService.saveBatch(appConfigItemInitData);
    }

    @Override
    public AppConfigListVO findAll() {
        LambdaQueryWrapper<TSubscribe> subscribeQuery = new LambdaQueryWrapper<>();
        List<TSubscribe> subscribeList = tSubscribeMapper.selectList(subscribeQuery);
        if (CollectionUtils.isEmpty(subscribeList)) {
            throw new BaseException(ErrorCode.LOCAL_CONFIG_ERROR);
        }
        Map<String, TSubscribe> subscribeMap = subscribeList.stream().collect(Collectors.toMap(TSubscribe::getSubscribeName, Function.identity()));

        LambdaQueryWrapper<TAppConfig> appConfigQuery = new LambdaQueryWrapper<>();
        List<TAppConfig> appConfigList = baseMapper.selectList(appConfigQuery);
        if (CollectionUtils.isEmpty(appConfigList)) {
            throw new BaseException(ErrorCode.LOCAL_CONFIG_ERROR);
        }
        Map<String, TAppConfig> appConfigMap = appConfigList.stream().collect(Collectors.toMap(TAppConfig::getConfigName, Function.identity()));
        TAppConfig subscribeConfig = appConfigMap.get(AppConfigNameEnum.SUBSCRIBE.getCode());

        TSubscribe subscribe7 = subscribeMap.get(SubscribeNameEnum.SUBSCRIBE_7.getCode());
        BigDecimal normalThreshold = subscribe7.getThreshold();
        AppConfigItemVO normalThresholdItemVo = new AppConfigItemVO();
        normalThresholdItemVo.setConfigId(subscribeConfig.getId());
        normalThresholdItemVo.setItemName(SubscribeNameEnum.SUBSCRIBE_LOWEST.getCode());
        normalThresholdItemVo.setItemValue(normalThreshold.toPlainString());
        normalThresholdItemVo.setRemark("认购最低消耗USDT");

        List<AppConfigItemVO> subscribeConfigItemVOList = new ArrayList<>(subscribeList.stream().map(subscribe -> {
            AppConfigItemVO itemVO = new AppConfigItemVO();
            itemVO.setConfigId(subscribeConfig.getId());
            itemVO.setItemName(subscribe.getSubscribeName());
            itemVO.setItemValue(subscribe.getDailyRateReturn().toPlainString());
            itemVO.setRemark(subscribe.getSubscribeNameCn());
            return itemVO;
        }).toList());
        subscribeConfigItemVOList.add(normalThresholdItemVo);

        AppConfigVO subscribeConfigVO = new AppConfigVO();
        BeanUtils.copyProperties(subscribeConfig, subscribeConfigVO);
        subscribeConfigVO.setConfigItems(subscribeConfigItemVOList);

        List<Long> appConfigIds = appConfigList.stream().map(TAppConfig::getId).toList();

        LambdaQueryWrapper<TAppConfigItem> appConfigItemQuery = new LambdaQueryWrapper<>();
        appConfigItemQuery.in(TAppConfigItem::getConfigId, appConfigIds);
        List<TAppConfigItem> appConfigItems = tAppConfigItemMapper.selectList(appConfigItemQuery);
        if (CollectionUtils.isEmpty(appConfigItems)) {
            throw new BaseException(ErrorCode.LOCAL_CONFIG_ERROR);
        }

        Map<Long, List<TAppConfigItem>> appConfigItemMap = appConfigItems.stream().collect(Collectors.groupingBy(TAppConfigItem::getConfigId));
        List<AppConfigVO> voList = appConfigList.stream().map(appConfig -> {
            AppConfigVO configVO = new AppConfigVO();
            BeanUtils.copyProperties(appConfig, configVO);

            List<TAppConfigItem> items = appConfigItemMap.get(appConfig.getId());
            List<AppConfigItemVO> itemVos = items.stream().map(item -> {
                AppConfigItemVO itemVO = new AppConfigItemVO();
                BeanUtils.copyProperties(item, itemVO);
                return itemVO;
            }).toList();
            configVO.setConfigItems(itemVos);

            return configVO;
        }).collect(Collectors.toList());

        voList.add(subscribeConfigVO);

        AppConfigListVO appConfigListVO = new AppConfigListVO();
        appConfigListVO.setAppConfigList(voList);
        return appConfigListVO;
    }

    @Override
    public boolean updateSubscribeConfig(UpdateSubscribeVO updateSubscribeVO) {
        List<SubscribeVO> subscribeVOList = updateSubscribeVO.getSubscribeVOList();
        AppConfigItemVO lowestItemVO = updateSubscribeVO.getLowest();
        boolean updateSubscribe = false;
        if(!CollectionUtils.isEmpty(subscribeVOList)){
            BigDecimal lowest = null;
            if(lowestItemVO!=null && StringUtils.isNotBlank(lowestItemVO.getItemValue())) {
                lowest = new BigDecimal(lowestItemVO.getItemValue());
            }
            final BigDecimal finalLowest = lowest;

            LambdaQueryWrapper<TSubscribe> subscribeQuery = new LambdaQueryWrapper<>();
            List<TSubscribe> subscribeList = tSubscribeMapper.selectList(subscribeQuery);
            if (CollectionUtils.isEmpty(subscribeList)) {
                throw new BaseException(ErrorCode.LOCAL_CONFIG_ERROR);
            }
            Map<String, SubscribeVO> subscribeMap = subscribeVOList.stream().collect(Collectors.toMap(SubscribeVO::getSubscribeName, Function.identity()));

            List<TSubscribe> updateList = subscribeList.stream().map(s->{
                TSubscribe tSubscribe = TSubscribe.builder()
                        .id(s.getId())
                        .build();
                SubscribeVO vo = subscribeMap.get(s.getSubscribeName());
                if(vo!=null){
                    if(StringUtils.isNotBlank(vo.getDailyRateReturn())) {
                        BigDecimal rate = new BigDecimal(vo.getDailyRateReturn()).divide(CommonConstants.HUNDRED, CommonConstants.DEFAULT_SCALE, RoundingMode.HALF_UP);
                        tSubscribe.setDailyRateReturn(rate);
                    }
                }
                if(finalLowest!=null && SubscribeLevelEnum.isNormal(s.getSubscribeLevel())){
                    tSubscribe.setThreshold(finalLowest);
                }
                return tSubscribe;
            }).toList();
            itSubscribeService.updateBatchById(updateList);

            updateSubscribe = true;
        }

        AppConfigItemVO showItemVO = updateSubscribeVO.getShow();
        if(showItemVO!=null && StringUtils.isNotBlank(showItemVO.getItemValue())){
            LambdaQueryWrapper<TAppConfigItem> itemQuery = new LambdaQueryWrapper<>();
            itemQuery.eq(TAppConfigItem::getItemName, AppConfigItemNameEnum.SUBSCRIBE_SHOW_SPECIAL.getCode());
            TAppConfigItem showItem = tAppConfigItemMapper.selectOne(itemQuery);
            if(showItem!=null) {
                TAppConfigItem showItemUpdate = TAppConfigItem.builder()
                        .id(showItem.getId())
                        .itemValue(showItemVO.getItemValue())
                        .build();
                tAppConfigItemMapper.updateById(showItemUpdate);
            }else{
                LambdaQueryWrapper<TAppConfig> appCfgQuery = new LambdaQueryWrapper<>();
                appCfgQuery.eq(TAppConfig::getConfigName, AppConfigNameEnum.SUBSCRIBE.getCode());
                TAppConfig config = tAppConfigMapper.selectOne(appCfgQuery);
                if(config!=null) {
                    TAppConfigItem newItem = TAppConfigItem.builder()
                            .configId(config.getId())
                            .itemName(AppConfigItemNameEnum.SUBSCRIBE_SHOW_SPECIAL.getCode())
                            .itemValue(showItemVO.getItemValue())
                            .build();
                    tAppConfigItemMapper.insert(newItem);
                }
            }
            updateSubscribe = true;
        }
        if(updateSubscribe){
            asyncExecutor.execute(()->itAppConfigItemService.initData());
        }
        return true;
    }

    @Override
    public boolean updateAppConfig(AppConfigVO vo) {
        List<AppConfigItemVO> itemVoList = vo.getConfigItems();
        if (CollectionUtils.isEmpty(itemVoList)) {
            return false;
        }
        List<String> itemNameList = itemVoList.stream().map(AppConfigItemVO::getItemName).toList();
        Map<String, String> itemNameValue = itemVoList.stream().collect(Collectors.toMap(AppConfigItemVO::getItemName, AppConfigItemVO::getItemValue));
        LambdaQueryWrapper<TAppConfigItem> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.in(TAppConfigItem::getItemName, itemNameList);
        List<TAppConfigItem> tAppConfigItemList = tAppConfigItemMapper.selectList(itemQuery);
        List<TAppConfigItem> updateList = tAppConfigItemList.stream().map(item -> {
            String name = item.getItemName();
            String itemValue = itemNameValue.get(item.getItemName());
            // 需要除以100的百分比数字
            if(AppConfigItemNameEnum.FUND_RETURN_RATE.getCode().equalsIgnoreCase(name)
                || AppConfigItemNameEnum.FUND_WITHDRAW_FEE.getCode().equalsIgnoreCase(name)
                    || AppConfigItemNameEnum.WITHDRAW_FEE.getCode().equalsIgnoreCase(name)
                    || AppConfigItemNameEnum.BALANCE_CONVERSION_FEE.getCode().equalsIgnoreCase(name)
            ){
                BigDecimal rate = new BigDecimal(itemValue).divide(CommonConstants.HUNDRED, CommonConstants.DEFAULT_SCALE, RoundingMode.HALF_UP);
                itemValue = rate.toPlainString();
            }
            TAppConfigItem tEntity = TAppConfigItem.builder()
                    .id(item.getId())
                    .itemValue(itemValue)
                    .build();
            return tEntity;
        }).toList();
        itAppConfigItemService.updateBatchById(updateList);

        asyncExecutor.execute(()->itAppConfigItemService.initData());

        return true;
    }
}
